package com.kongjs.common.rest.util;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kongjs.common.rest.exception.DeserializeException;
import com.kongjs.common.rest.exception.SerializeException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
public class JsonUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private static ObjectMapper mapper = new ObjectMapper();

    public static String toJson(Object obj) {
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new DeserializeException(e.getMessage(), e);
        }
    }

    public static <T> T fromJson(String json, Class<T> clazz) {
        try {
            return mapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new SerializeException(e.getMessage(), e);
        }
    }

    public static <T> T fromJson(String json, TypeReference<T> typeReference) {
        try {
            return mapper.readValue(json, typeReference);
        } catch (Exception e) {
            throw new DeserializeException(e.getMessage(), e);
        }
    }

    public static <K, V> Map<K, V> fromJsonToMap(String json) {
        return fromJson(json, new TypeReference<>() {
        });
    }

    public static <T> List<T> fromJsonToList(String json) {
        return fromJson(json, new TypeReference<>() {
        });
    }

    public static <T> Set<T> fromJsonToSet(String json) {
        return fromJson(json, new TypeReference<>() {
        });
    }

    public static void writeJson(OutputStream out, Object obj) {
        try {
            mapper.writeValue(out, obj);
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void writeJson(Writer out, Object obj) {
        try {
            mapper.writeValue(out, obj);
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        JsonUtils.applicationContext = applicationContext;
        JsonUtils.mapper = applicationContext.getBean(ObjectMapper.class);
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
    }
}
